package logic

import (
	"common"
	"common/biz"
	"common/logs"
	"context"
	"core/service"
	"fmt"
	"framework/msError"
	"framework/remote"
	"game/component"
	"game/component/proto"
	"game/models/request"
	"hall/logic"
	"hall/models/response"
	"math/rand"
	"sync"
	"time"
)

type CardManager struct {
	sync.RWMutex
	RoomList map[string]*component.Room
	joinCh   chan *JoinChan
	manager  *logic.Manager
}

type JoinChan struct {
	session *remote.Session
	data    *response.GameRoleInfo
	room    *component.Room
}

func (m *CardManager) CreateRoom(session *remote.Session, req *request.CreateRoomReq, userData *response.GameRoleInfo, gameService *service.GameService) *msError.Error {
	isOpen := gameService.GetConfInfo(context.TODO(), req.ID, "is_open")
	if isOpen.Value == "0" {
		logs.Error("[Game]用户%d FleeBetting err:系统关闭游戏 req=%v", userData.UID, req)
		return biz.GameNotEnabledError
	}
	m.Lock()
	defer m.Unlock()
	// 1. 需要创建一个房间 生成一个房间号
	roomId := m.createRoomId()
	newRoom := component.NewRoom(roomId, req.GameRule, req.ID, m, gameService)
	m.RoomList[roomId] = newRoom
	return newRoom.UserEntryRoom(session, userData)
}

func (m *CardManager) JoinRoom(session *remote.Session, roomID string, userData *response.GameRoleInfo, gameService *service.GameService) *msError.Error {
	isOpen := gameService.GetConfInfo(context.TODO(), 1, "is_open")
	if isOpen.Value == "0" {
		logs.Error("[Game]用户%d FleeBetting err:系统关闭游戏", userData.UID)
		return biz.GameNotEnabledError
	}
	m.RLock()
	defer m.RUnlock()
	r, ok := m.RoomList[roomID]
	if ok {
		rule := r.GetGameRule()
		if userData.Gold < rule.BaseScore {
			logs.Error("[Game]用户%d JoinRoom err:游戏币数量不足 req=%v", userData.UID, userData)
			return biz.GameRoomError
		}
		joinChan := new(JoinChan)
		joinChan.session = session
		joinChan.data = userData
		joinChan.room = r
		if len(r.GetUsers()) >= 6 {
			return biz.SqlError
		}
		m.joinCh <- joinChan
		//return r.UserEntryRoom(session, userData)

		return nil
	}
	return biz.RoomNotExist
}

func (m *CardManager) DismissRoom(roomId string) {
	m.Lock()
	defer m.Unlock()
	delete(m.RoomList, roomId)
}

// createRoomId 递归返回不存在的房间号
func (m *CardManager) createRoomId() string {
	// 随机数的方式去创建
	roomId := m.genRoomId()
	_, ok := m.RoomList[roomId]
	if ok {
		return m.createRoomId()
	}
	return roomId
}

// genRoomId 生成一个6位的随机数
func (m *CardManager) genRoomId() string {
	rand.New(rand.NewSource(time.Now().UnixMilli()))
	// 房间号是6位数
	roomIdInt := rand.Int63n(999999)
	if roomIdInt < 100000 {
		roomIdInt += 100000
	}
	return fmt.Sprintf("%d", roomIdInt)
}

func (m *CardManager) GetRoomById(roomId string) *component.Room {
	r, ok := m.RoomList[roomId]
	if ok {
		return r
	}
	return nil
}

func (m *CardManager) GetRoom(num int) []map[string]any {
	roomData := m.getRoomData()
	if len(m.RoomList) <= num {
		return roomData
	}
	rand.Seed(time.Now().UnixNano())
	room := roomData
	rooms := make([]map[string]any, 0)
	for len(rooms) < num {
		logs.Info("%d   - res %v", len(room), room)
		index := 1
		if len(room) != 0 {
			index = rand.Intn(len(room))
		}
		if room[index] == nil {
			continue
		}
		rooms = append(rooms, room[index])
		room = append(room[:index], room[index+1:]...)
	}
	return rooms
}

func (m *CardManager) getRoomData() []map[string]any {
	m.RLock()
	defer m.RUnlock()
	var roomData = make([]map[string]any, 0)
	for k, v := range m.RoomList {
		if v.GetGameStatus() {
			continue
		}
		roomData = append(roomData, map[string]any{
			"roomID":         k,
			"peopleNum":      len(v.GetUsers()),
			"totalPeopleNum": v.GetGameRule().MaxPlayerCount,
			"BaseScore":      v.GetGameRule().BaseScore,
		})
	}
	return roomData
}

func (m *CardManager) run() {
	go func() {
		for {
			select {
			case data := <-m.joinCh:
				err := data.room.UserEntryRoom(data.session, data.data)
				if err != nil {
					logs.Error("%v", err)
					m.manager.ServerMessagePush([]string{data.session.GetUid()}, proto.RoomErrorNotifyData(common.F(err)), data.session)
				}
			}
		}
	}()
}

func NewCardManager() *CardManager {
	c := &CardManager{
		RoomList: make(map[string]*component.Room),
		joinCh:   make(chan *JoinChan, 1024),
		manager:  logic.NewManager(),
	}
	c.run()
	return c
}
